package com.hyt.it.ogt.pj.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.hyt.core.base.BaseServiceImpl;
import com.hyt.core.util.UUIDUtils;
import com.hyt.it.ogt.data.enums.SubjectMarkTypeEnums;
import com.hyt.it.ogt.pj.common.Constants;
import com.hyt.it.ogt.pj.common.MarkException;
import com.hyt.it.ogt.pj.common.ResponseCode;
import com.hyt.it.ogt.pj.enums.CommonEnums;
import com.hyt.it.ogt.pj.enums.ProjectDownLoadFileTypeEnum;
import com.hyt.it.ogt.pj.mapper.ProjectMapper;
import com.hyt.it.ogt.pj.mapper.SubjectScoreMapper;
import com.hyt.it.ogt.pj.model.dto.paper.*;
import com.hyt.it.ogt.pj.model.dto.pj.*;
import com.hyt.it.ogt.pj.model.entity.*;
import com.hyt.it.ogt.pj.model.param.ExamExpertSettingParam;
import com.hyt.it.ogt.pj.model.vo.*;
import com.hyt.it.ogt.pj.service.*;
import com.hyt.loginfo.service.IBaseLoginService;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 * <p>
 * 评卷项目表 服务实现类
 * </p>
 *
 * @author qiaozj
 * @since 2020-07-09
 */
@Service
public class ProjectDfyhServiceImpl extends BaseServiceImpl<ProjectMapper, Project> implements IProjectDfyhService {

    protected Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private ISubjectService subjectService;

    @Autowired
    private IPaperService paperService;

    @Autowired
    private IStudentService studentService;

    @Autowired
    private IPieceService pieceService;

    @Autowired
    private ITaskService taskService;

    @Autowired
    private IPieceItemService pieceItemService;

    @Autowired
    private IPaperItemService paperItemService;

    @Autowired
    private ISubjectScoreService subjectScoreService;

    @Autowired
    private IPieceScoreService pieceScoreService;

    @Autowired
    private IProjectService projectService;

    @Autowired
    private IStudentConfigService studentConfigService;

    @Autowired
    private IExamExpertService examExpertService;

    @Autowired
    private SubjectScoreMapper subjectScoreMapper;

    @Autowired
    private IProjectSettingService projectSettingService;

    @Autowired
    private ProjectMapper projectMapper;

    @Autowired
    private IPaperItemFileService paperItemFileService;

    @Autowired
    private IProjectDataDownLoadRecordService projectDataDownLoadRecordService;
    @Resource
    IBaseLoginService iBaseLoginService;

    @Override
    public Page<ProjectNewVo> page(Page<ProjectNewVo> pageParam,
                                   String projectName,
                                   Integer markStatus,
                                   String officeId,
                                   Integer classfication,
                                   Integer ptBindingStatus,
                                   Integer projectDataType) {
        Set<String> deptIds = iBaseLoginService.getDeptIds();
        Page<ProjectNewVo> projectNewVoPage = projectMapper.pageNew(pageParam, projectName, markStatus, officeId, classfication, ptBindingStatus, projectDataType, deptIds);
        if (CollectionUtils.isEmpty(projectNewVoPage.getRecords())) {
            return projectNewVoPage;
        }

        //客观题成绩
        Set<String> projectIds = projectNewVoPage.getRecords().stream().map(p -> p.getProjectId()).collect(Collectors.toSet());
        LambdaQueryWrapper<SubjectScore> subjectScoreQueryWrapper = new LambdaQueryWrapper<>();
        subjectScoreQueryWrapper.in(SubjectScore::getProjectId, projectIds);
        List<SubjectScore> subjectScores = subjectScoreMapper.selectList(subjectScoreQueryWrapper);
        Map<String, List<SubjectScore>> subjectScoreMap = subjectScores.stream().collect(Collectors.groupingBy(SubjectScore::getProjectId));

        List<ProjectDataDownLoadRecord> projectDataDownLoadZipRecords = projectDataDownLoadRecordService.getIsRunningDownloadZip(projectIds, ProjectDownLoadFileTypeEnum.project_all_zip.getType());
        Map<String, ProjectDataDownLoadRecord> runningDownLoadZipRecordsMap = new HashMap<String, ProjectDataDownLoadRecord>();
        if (!org.apache.commons.collections4.CollectionUtils.isEmpty(projectDataDownLoadZipRecords)) {
            runningDownLoadZipRecordsMap = projectDataDownLoadZipRecords.stream().collect(Collectors.toMap(s -> (s.getProjectId()), projectDataDownLoadRecord -> projectDataDownLoadRecord, (key1, key2) -> key2));
        }
        List<ProjectDataDownLoadRecord> projectDataDownLoadObscereRecords = projectDataDownLoadRecordService.getIsRunningDownloadZip(projectIds, ProjectDownLoadFileTypeEnum.project_objective_score.getType());
        Map<String, ProjectDataDownLoadRecord> runningDownLoadObScoreRecordsMap = new HashMap<String, ProjectDataDownLoadRecord>();
        if (!org.apache.commons.collections4.CollectionUtils.isEmpty(projectDataDownLoadObscereRecords)) {
            runningDownLoadZipRecordsMap = projectDataDownLoadObscereRecords.stream().collect(Collectors.toMap(s -> (s.getProjectId()), projectDataDownLoadRecord -> projectDataDownLoadRecord, (key1, key2) -> key2));
        }
        // 获取项目下的所有客观题列表
        Map<String, List<PaperItem>> projectObjectiveItemMap = paperItemService.selectAllObjectiveItemsByProjectIds(new ArrayList<String>(projectIds));
        // 获取所有项目的音视频列表
        List<PaperItemFile> paperItemFileList = paperItemFileService.query().groupBy("project_id").list();
        for (ProjectNewVo projectVo : projectNewVoPage.getRecords()) {
            projectVo.setShowObjScoreButton(1);
            if (!MapUtils.isEmpty(subjectScoreMap) && null != subjectScoreMap.get(projectVo.getProjectId())) {
                Set<BigDecimal> scores = subjectScoreMap.get(projectVo.getProjectId()).stream().filter(
                        s -> null != s.getObjectiveScore()).map(s -> s.getObjectiveScore()).collect(Collectors.toSet());
                if (org.apache.commons.collections4.CollectionUtils.isEmpty(scores)) {
                    projectVo.setShowObjScoreButton(0);
                }
            }

            ProjectDataDownLoadRecord runningZipRecord = runningDownLoadZipRecordsMap.get(projectVo.getProjectId());
            if (null != runningZipRecord) {
                projectVo.setRunningDownLoadZipTask(Boolean.TRUE);
            }
            ProjectDataDownLoadRecord runningObScoreRecord = runningDownLoadObScoreRecordsMap.get(projectVo.getProjectId());
            if (null != runningObScoreRecord) {
                projectVo.setRunningDownLoadObScoreTask(Boolean.TRUE);
            }
            // 是否有客观题
            List<PaperItem> objectiveItems = projectObjectiveItemMap.get(projectVo.getProjectId());
            if (org.apache.commons.collections4.CollectionUtils.isEmpty(objectiveItems)) {
                projectVo.setHasObjectiveItems(Boolean.FALSE);
            }
            // 是否有音视频文件
            if (CollectionUtil.isNotEmpty(paperItemFileList)) {
                long count = paperItemFileList.stream().filter(item -> projectVo.getProjectId().equals(item.getProjectId())).count();
                if (count > 0) {
                    projectVo.setHasPaperItemFile(Boolean.TRUE);
                }
            }
        }
        return projectNewVoPage;
    }

    @Override
    public ProjectOverviewVo getOverViewData(String projectId) {
        ProjectOverviewVo projectOverviewVo = this.baseMapper.getOverView(projectId);

        // 设置studentNum
        List<Student> students = studentService.selectByProject(projectId);
        if (CollectionUtil.isNotEmpty(students)) {
            long studentNum = students.stream().map(item -> item.getAdmissionNum()).distinct().count();
            projectOverviewVo.setStudentNum(studentNum);
        }

        // 设置subjectNum
        List<Subject> subjects = subjectService.selectByProjectId(projectId);
        if (CollectionUtil.isNotEmpty(subjects)) {
            long subjectNum = subjects.stream().map(item -> item.getSubjectId()).distinct().count();
            projectOverviewVo.setSubjectNum(subjectNum);
        }

        // 设置paperNum
        List<Paper> papers = paperService.selectBySubject(projectId, null);
        if (CollectionUtil.isNotEmpty(papers)) {
            long paperNum = papers.stream().map(item -> item.getId()).distinct().count();
            projectOverviewVo.setPaperNum(paperNum);
        }

        //无考场目前没有类型，默认未其他
        if (CommonEnums.EXAM_CLASSFICATION_0.getCode().equals(projectOverviewVo.getExamClassfication())) {
            projectOverviewVo.setExamTypeName(Constants.MARK_OTHER);
            projectOverviewVo.setBatchName("");
        } else {
            if (StringUtils.isNotEmpty(projectOverviewVo.getExamTypeName())) {
                projectOverviewVo.setExamTypeName(projectOverviewVo.getExamTypeName().replaceAll(",", "--"));
            }

        }
        List<PaperItem> paperItemSubjective = paperItemService.getPaperItemSubjective(projectId, null);
        projectOverviewVo.setQuestionNum(paperItemSubjective.size());
        return projectOverviewVo;
    }

    @Override
    public ProjectNewVo getProjectNewVoById(String projectId, String officeId) {
        ProjectNewVo projectOverviewVo = projectMapper.getProjectNewVoById(projectId, officeId);
        return projectOverviewVo;
    }

    @Override
    public List<ProjectNewVo> getProjectNewVoByIds(String projectIds, String officeId) {
        if (StringUtils.isEmpty(projectIds)) {
            return null;
        }
        List<String> ids = Arrays.asList(projectIds.split(","));
        if (CollectionUtils.isEmpty(ids)) {
            return null;
        }
        List<ProjectNewVo> projectOverviewVo = projectMapper.getProjectNewVoByIds(ids, officeId);
        return projectOverviewVo;
    }

    @Override
    public Boolean updateProjectPtBindingStatus(String projectId, Integer bindingStatus) {
        Project project = projectMapper.selectById(projectId);
        if (null == project) {
            return Boolean.FALSE;
        }
        project.setPtBindingStatus(bindingStatus);
        int result = projectMapper.updateById(project);
        if (result > 0) {
            return Boolean.TRUE;
        } else {
            return Boolean.FALSE;
        }
    }


    @Override
    public Page<MarkProgress1Vo> markProgressPage(Page<MarkProgress1Vo> pageParam,
                                                  String projectId,
                                                  String subjectId,
                                                  String placeId,
                                                  String roomId) {

        // 评卷模式（0：按科目评卷，1：按批次评卷，2：按考场评卷
        List<ProjectSetting> projectSettings = projectSettingService.lambdaQuery().eq(ProjectSetting::getProjectId, projectId).list();
        String markModel = "";
        if (!CollectionUtils.isEmpty(projectSettings)) {
            markModel = projectSettings.get(0).getMarkModel();
        }

        Page<MarkProgress1Vo> markProgress1VoPage = this.baseMapper.markProgressPage(pageParam, projectId, subjectId, placeId, roomId, markModel);
        List<MarkProgress1Vo> records = markProgress1VoPage.getRecords();
        if (CollectionUtils.isEmpty(records)) {
            return markProgress1VoPage;
        }

        // 处理其他数据
        for (MarkProgress1Vo item : records) {
            // 完成率
            BigDecimal completeNum = new BigDecimal(item.getCompleteNum() == null ? 0 : item.getCompleteNum());
            BigDecimal pieceNum = new BigDecimal(item.getPieceNum() == null ? 0 : item.getPieceNum());
            item.setCompleteRate(completeNum.divide(pieceNum, 4, RoundingMode.HALF_UP));
            // 查询专家
            item.setExperts(examExpertService.queryExpertBySubject(projectId, subjectId, item.getRoomId(), markModel));
            // 获取主观题总分
            item.setPaperScore(paperItemService.getPaperSubjectiveScore(projectId, subjectId));
            // 这里注释调，取piece_score里的分数
            /* List<SubjectScore> subjectScoreList = subjectScoreService.lambdaQuery().eq(SubjectScore::getProjectId, projectId)
                    .eq(SubjectScore::getSubjectId, subjectId).isNotNull(SubjectScore::getSubjectiveScore).orderByDesc(SubjectScore::getSubjectiveScore).list();
            if(!CollectionUtils.isEmpty(subjectScoreList)) {
                item.setTopScore(subjectScoreList.get(0).getSubjectiveScore());
                item.setLowScore(CollectionUtils.lastElement(subjectScoreList).getSubjectiveScore());
            }*/
            // 科目名称
            Subject subject = subjectService.lambdaQuery().eq(Subject::getSubjectId, item.getSubjectId()).last("LIMIT 1").one();
            if (null != subject) {
                item.setSubjectName(subject.getSubjectName());
            }
            // 待评卷数量
            item.setUnmarkNum(item.getPieceNum() - item.getCompleteNum());
        }
        return markProgress1VoPage;
    }

    @Override
    public Page<MarkProgress2Vo> markProgress2Page(Page<MarkProgress2Vo> pageParam,
                                                   String projectId,
                                                   String subjectId,
                                                   String expertName) {
        Page<MarkProgress2Vo> markProgress2VoPage = this.baseMapper.markProgress2Page(pageParam, projectId, subjectId, expertName);
        List<MarkProgress2Vo> records = markProgress2VoPage.getRecords();
        for (MarkProgress2Vo item : records) {
            // 待评卷量
            item.setUnmarkNum(item.getPieceNum() - item.getCompleteNum());
            // 完成率
            BigDecimal completeNum = new BigDecimal(item.getCompleteNum() == null ? 0 : item.getCompleteNum());
            BigDecimal pieceNum = new BigDecimal(item.getPieceNum() == null ? 0 : item.getPieceNum());
            item.setCompleteRate(completeNum.divide(pieceNum, 4, RoundingMode.HALF_UP));
            // 总分（试卷主观题分）
            item.setPaperScore(paperItemService.getPaperSubjectiveScore(projectId, subjectId));
        }
        return markProgress2VoPage;
    }

    @Override
    public List<OptionItemVo> getBatchByProject(String projectId) {
        return this.baseMapper.getBatchByProject(projectId);
    }

    @Override
    public List<OptionItemVo> getSubjectByProject(String projectId, SubjectMarkTypeEnums subjectMarkTypeEnums) {
        return this.baseMapper.getSubjectByProject(projectId, subjectMarkTypeEnums.getCode());
    }

    @Override
    public List<OptionItemVo> getPlaceByProject(String projectId) {
        return this.baseMapper.getPlaceByProject(projectId);
    }

    @Override
    public List<OptionItemVo> getRoomByProject(String projectId, String placeId) {
        return this.baseMapper.getRoomByProject(projectId, placeId);
    }

    @Override
    public void projectPushCheck(String examId) {
        // 查询是否有分配评卷，如果有则不允许推送
        List<Piece> list = pieceService.lambdaQuery().eq(Piece::getProjectId, examId).eq(Piece::getDelFlag, false).list();
        for (Piece piece : list) {
            int size = pieceScoreService.lambdaQuery().eq(PieceScore::getPieceId, piece.getId()).list().size();
            if (size > 0) {
                throw new MarkException(ResponseCode.KW_MARK_NOT_PERMIT_PUSH.toString());
            }
        }
    }

    @Override
    public void examTypeChangeCheck(String examId) {
        Project project = projectService.getById(examId);
        if (null == project) {
            // throw new MarkException(ResponseCode.PROJECT_NO_FOUND.toString());
            // 为空暂时直接返回
            return;
        }
        // 查询是否有评卷记录，如果有则不允许推送
        List<Piece> list = pieceService.lambdaQuery().eq(Piece::getProjectId, examId).eq(Piece::getDelFlag, false).list();
        for (Piece piece : list) {
            int size = pieceScoreService.lambdaQuery().eq(PieceScore::getPieceId, piece.getId()).list().size();
            if (size > 0) {
                throw new MarkException(ResponseCode.KW_EXAM_TYPE_CHANGE_ERROR.toString());
            }
        }
        // 允许修改，删除数据
        deleteProjectAllData(examId);
    }

    @Override
    public List<OptionItemVo> getExpertSubject(ExamExpertSettingParam param, String userId) {
        //全部的任务
        List<Task> tasks = taskService.getTaskSubjects(param.getProjectId(), param.getBatchId(), param.getRoomId());
        Set<String> ids = tasks.stream().map(Task::getId).collect(Collectors.toSet());
        //登录人的任务
        List<PieceScore> pieceScores = pieceScoreService.lambdaQuery().in(PieceScore::getTaskId, ids).eq(PieceScore::getUserId, userId).list();
        Set<String> taskIds = pieceScores.stream().map(PieceScore::getTaskId).collect(Collectors.toSet());
        Iterator<Task> iterator = tasks.iterator();
        while (iterator.hasNext()) {
            Task task = iterator.next();
            if (!taskIds.contains(task.getId())) {
                iterator.remove();
            }
        }

        Set<String> subjectIds = tasks.stream().map(Task::getSubjectId).collect(Collectors.toSet());
        List<OptionItemVo> optionItemVos = pieceScoreService.getExpertSubject(param.getProjectId(), userId);
        if (CollectionUtils.isEmpty(subjectIds) || CollectionUtils.isEmpty(optionItemVos)) {
            return Collections.EMPTY_LIST;
        }
        List<OptionItemVo> retOptionItemVos = new ArrayList<>();
        for (OptionItemVo optionItemVo : optionItemVos) {
            if (subjectIds.contains(optionItemVo.getCode())) {
                retOptionItemVos.add(optionItemVo);
            }
        }
        return retOptionItemVos;
    }

    @Override
    public List<OptionItemVo> getExpertPlace(String projectId, String officeId) {
        return pieceScoreService.getExpertPlace(projectId, officeId);
    }

    @Override
    public List<OptionItemVo> getExpertRoom(String projectId, String palceId) {
        return taskService.getExpertRoom(projectId, palceId);
    }

    static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
        Map<Object, Boolean> seen = new ConcurrentHashMap<>();
        return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void projectDataPush(PjProjectCandidatePushDTO pjProjectCandidatePushDTO) {
        logger.info(">>>接收到的推送评卷任务数据:{}", JSONObject.toJSONString(pjProjectCandidatePushDTO));

        String examId = pjProjectCandidatePushDTO.getPjProjectInfoDTO().getBatchId();
        // 0、判断是否允许推送
        projectPushCheck(examId);

        // 1、重复推送直接删除已保存数据（现考现评一次性推送，不存在增量的情况）
        deleteProjectAllData(examId);

        // 2、保存项目
        PjProjectInfoDTO pjProjectInfoDTO = pjProjectCandidatePushDTO.getPjProjectInfoDTO();
        transferAndSaveProject(pjProjectInfoDTO);

        // 2、保存科目
        PjProjectSubjectDTO pjProjectSubjectDTO = pjProjectCandidatePushDTO.getPjProjectSubjectDTO();
        transferAndSaveSubject(pjProjectSubjectDTO);

        // 3、保存试卷
        PaperDataDTO paperDataDTO = pjProjectCandidatePushDTO.getPaper();
        PaperAndItemDataDTO paperAndItemDataDTO = transferAndSavePaper(paperDataDTO, examId);

        // 4、生成评卷块
        Piece piece = transferAndSavePiece(paperAndItemDataDTO, pjProjectInfoDTO, examId);

        // 5、保存考生
        List<PjCandidateDTO> candidateDTOS = pjProjectCandidatePushDTO.getCandidateDTOS();
        transferAndSaveStudent(paperAndItemDataDTO, candidateDTOS, piece);

    }


    /**
     * 转换数据并保存项目信息
     *
     * @param pjProjectInfoDTO
     */
    private void transferAndSaveProject(PjProjectInfoDTO pjProjectInfoDTO) {
        logger.info(">>>开始保存项目信息:" + JSONObject.toJSONString(pjProjectInfoDTO));
        Project project = new Project();
        project.setId(pjProjectInfoDTO.getBatchId());
        project.setProjectName(pjProjectInfoDTO.getBatchName());
        project.setTaskId(pjProjectInfoDTO.getExamId());
        project.setTaskName(pjProjectInfoDTO.getExamName());
        project.setOfficeId(pjProjectInfoDTO.getOfficeId());
        project.setDeptId(pjProjectInfoDTO.getDeptId());
        project.setExamType(pjProjectInfoDTO.getExamType());
        project.setExamTypeName(pjProjectInfoDTO.getExamTypeName());
        project.setVersion(CommonEnums.PROJECT_VERSION_1.getCode());
        project.setBeginDate(pjProjectInfoDTO.getBeginDate());
        project.setEndDate(pjProjectInfoDTO.getEndDate());
        project.setTaskBeginDate(pjProjectInfoDTO.getTaskBeginDate());
        project.setTaskEndDate(pjProjectInfoDTO.getTaskEndDate());
        project.setExamClassfication(CommonEnums.EXAM_CLASSFICATION_2.getCode());
        project.setMarkPublish(CommonEnums.TASK_PUBLISH_STATUS_0.getCode());
        projectService.save(project);
    }

    /**
     * 转换数据并保存科目信息
     *
     * @param pjProjectSubjectDTO
     */
    private void transferAndSaveSubject(PjProjectSubjectDTO pjProjectSubjectDTO) {
        logger.info(">>>开始保存科目信息:" + JSONObject.toJSONString(pjProjectSubjectDTO));
        Subject subject = new Subject();
        subject.setSubjectId(pjProjectSubjectDTO.getSubjectId());
        subject.setSubjectName(pjProjectSubjectDTO.getSubjectName());
        subject.setProjectId(pjProjectSubjectDTO.getBatchId());
        subjectService.save(subject);
    }

    /**
     * 转换数据并保存试卷信息
     *
     * @param paperDataDTO
     */
    private PaperAndItemDataDTO transferAndSavePaper(PaperDataDTO paperDataDTO, String projectId) {
        logger.info(">>>开始保存试卷信息:" + JSONObject.toJSONString(paperDataDTO));
        String paperId = paperDataDTO.getPaperId();
        Paper paper = new Paper();
        paper.setPaperId(paperId);
        paper.setPaperVersion(paperDataDTO.getPaperVersion());
        paper.setPaperName(paperDataDTO.getPaperName());
        paper.setProjectId(projectId);
        paper.setSubjectId(paperDataDTO.getSubjectId());
        paper.setPaperScore(paperDataDTO.getPaperScore());
        paper.setObjectiveScore(paperDataDTO.getObjectiveItemScore());
        paper.setSubjectiveScore(paperDataDTO.getSubjectiveItemScore());
        paperService.save(paper);
        // 初始化试题
        List<PaperItem> paperItems = initPaperItem(paperDataDTO, paper);
        PaperAndItemDataDTO paperAndItemDataDTO = new PaperAndItemDataDTO();
        paperAndItemDataDTO.setPaper(paper);
        paperAndItemDataDTO.setPaperItems(paperItems);
        return paperAndItemDataDTO;
    }

    /**
     * 转换数据并保存考生信息
     *
     * @param candidateDTOS
     */
    private void transferAndSaveStudent(PaperAndItemDataDTO paperAndItemDataDTO, List<PjCandidateDTO> candidateDTOS, Piece piece) {
        logger.info(">>>开始保存学生信息和评卷任务信息:" + JSONObject.toJSONString(candidateDTOS));
        List<Student> studentList = new LinkedList<>();
        List<Task> taskList = new LinkedList<>();
        List<SubjectScore> subjectScoreList = new LinkedList<>();
        for (PjCandidateDTO pjCandidateDTO : candidateDTOS) {
            String officeId = pjCandidateDTO.getOfficeId();
            String deptId = pjCandidateDTO.getDeptId();
            String admissionNum = pjCandidateDTO.getAdmissionNum();
            String batchId = pjCandidateDTO.getBatchId();
            String batchName = pjCandidateDTO.getBatchName();
            String paperId = paperAndItemDataDTO.getPaper().getId();
            Integer paperVersion = pjCandidateDTO.getPaperVersion();
            String placeId = pjCandidateDTO.getPlaceId();
            String placeName = pjCandidateDTO.getPlaceName();
            String projectId = pjCandidateDTO.getBatchId();
            String roomId = pjCandidateDTO.getRoomId();
            String roomName = pjCandidateDTO.getRoomName();
            String seatNo = pjCandidateDTO.getSeatNo();
            String studentName = pjCandidateDTO.getStudentName();
            String subjectId = pjCandidateDTO.getSubjectId();
            String subjectName = pjCandidateDTO.getSubjectName();
            String cityCode = pjCandidateDTO.getCityCode();
            String cityName = pjCandidateDTO.getCityName();
            String provinceCode = pjCandidateDTO.getProvinceCode();
            String provinceName = pjCandidateDTO.getProvinceName();
            String districtCode = pjCandidateDTO.getDistrictCode();
            String districtName = pjCandidateDTO.getDistrictName();
            List<PjConfigCode> configs = pjCandidateDTO.getConfigs();

            // 创建student
            Student student = new Student();
            student.setOfficeId(officeId);
            student.setDeptId(deptId);
            student.setProjectId(projectId);
            student.setSubjectId(subjectId);
            student.setPaperId(paperId);
            student.setPaperVersion(paperVersion);
            student.setStudentName(studentName);
            student.setAdmissionNum(admissionNum);
            student.setEncodeId(admissionNum);
            student.setCityCode(cityCode);
            student.setCityName(cityName);
            student.setProvinceCode(provinceCode);
            student.setProvinceName(provinceName);
            student.setDistrictCode(districtCode);
            student.setDistrictName(districtName);
            // 考生配置信息
            List<StudentConfig> pjConfigCodeList = new LinkedList<>();
            for (PjConfigCode pjConfigCode : configs) {
                student.setCandidateId(pjConfigCode.getCandidateId());
                StudentConfig studentConfig = new StudentConfig();
                studentConfig.setAdmissionNum(admissionNum);
                studentConfig.setCandidateId(pjConfigCode.getCandidateId());
                studentConfig.setConfigCode(pjConfigCode.getConfigCode());
                studentConfig.setConfigId(pjConfigCode.getCjConfigID());
                studentConfig.setConfigValue(pjConfigCode.getConfigValue());
                studentConfig.setProjectId(projectId);
                pjConfigCodeList.add(studentConfig);
                // 保存一些主要的配置信息
                if ("性别".equals(pjConfigCode.getConfigCode())) {
                    student.setSex(pjConfigCode.getConfigValue());
                }
                if ("证件号码".equals(pjConfigCode.getConfigCode())) {
                    student.setIdNo(pjConfigCode.getConfigValue());
                }
                if ("手机号".equals(pjConfigCode.getConfigCode())) {
                    student.setTelephone(pjConfigCode.getConfigValue());
                }
                if ("证件照".equals(pjConfigCode.getConfigCode()) || "个人照片".equals(pjConfigCode.getConfigCode())) {
                    String configValue = pjConfigCode.getConfigValue();
                    if (!StringUtils.isEmpty(configValue)) {
                        student.setAvatar(configValue.split(",")[0]);
                    }
                }
                logger.info(">>>>>考生信息：{}", student);
            }
            studentList.add(student);
            studentConfigService.saveBatch(pjConfigCodeList);

            // 创建task
            Task task = new Task();
            task.setOfficeId(officeId);
            task.setDeptId(deptId);
            task.setProjectId(projectId);
            task.setSubjectId(subjectId);
            task.setPieceId(piece.getId());
            task.setEncodeId(admissionNum);
            task.setAdmissionNum(admissionNum);
            task.setMarkStatus(CommonEnums.TASK_MARK_STATUS_0.getCode());
            task.setBatchId(batchId);
            task.setBatchName(batchName);
            task.setPlaceId(placeId);
            task.setPlaceName(placeName);
            task.setRoomId(roomId);
            task.setRoomName(roomName);
            task.setSeatNo(seatNo);
            task.setAbsent(CommonEnums.STUDENT_ABSENT_0.getCode());
            taskList.add(task);

            // 创建 pj_subject_score
            SubjectScore subjectScore = new SubjectScore();
            subjectScore.setProjectId(projectId);
            subjectScore.setSubjectId(subjectId);
            subjectScore.setSubjectName(subjectName);
            subjectScore.setEncodeId(admissionNum);
            subjectScore.setAdmissionNum(admissionNum);
            subjectScoreList.add(subjectScore);
        }
        studentService.saveBatch(studentList);
        taskService.saveBatch(taskList);
        subjectScoreService.saveBatch(subjectScoreList);
        logger.info(">>>保存学生信息和评卷任务信息完成");
    }

    /**
     * 初始化试题
     *
     * @param paperDataDTO
     * @param paper
     */
    private List<PaperItem> initPaperItem(PaperDataDTO paperDataDTO, Paper paper) {
        String paperId = paper.getId();
        List<TopicDataDTO> topicDataList = paperDataDTO.getTopicDataList();
        List<PaperItem> paperItems = new ArrayList<>();
        for (TopicDataDTO topicDataDTO : topicDataList) {
            PaperItem paperItem = new PaperItem();
            paperItem.setId(UUIDUtils.newSortUUID());
            paperItem.setTopicId(topicDataDTO.getTopicId());
            paperItem.setPaperId(paperId);
            paperItem.setParentId("0");
            paperItem.setItemName(topicDataDTO.getTopicName());
            paperItem.setItemCode(topicDataDTO.getSort().toString());
            paperItem.setIsComposite(true);
            paperItem.setItemType("topic");
            paperItem.setItemLevel(0);
            // 设置题干
            paperItem.setItemStem(topicDataDTO.getTopicDescription());
            // 设置试题分数
            paperItem.setScore(topicDataDTO.getTopicScore());
            // 设置排序
            paperItem.setOrderNum(topicDataDTO.getSort());
            paperItems.add(paperItem);
            addChildItems(paperItem.getId(), topicDataDTO, paperItems, paper);
            // 保存题目附件信息
            savePaperItemFile(topicDataDTO.getItemDataList(), paper);
        }
        paperItemService.saveBatch(paperItems);
        return paperItems;
    }

    /**
     * 保存题目信息
     *
     * @param itemDataList
     * @param paper
     */
    private void savePaperItemFile(List<ItemDataDTO> itemDataList, Paper paper) {
        for (ItemDataDTO itemDataDTO : itemDataList) {
            List<ResourceAttr> stemAttrs = itemDataDTO.getStemAttrs();
            List<ResourceAttr> answerAttrs = itemDataDTO.getAnswerAttrs();
            List<ResourceAttr> descriptionAttrs = itemDataDTO.getDescriptionAttrs();
            // 合并集合
            List<ResourceAttr> resourceAttrList = new ArrayList<>();
            if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(resourceAttrList)) {
                resourceAttrList = CollectionUtil.unionAll(resourceAttrList, stemAttrs);
            }
            if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(answerAttrs)) {
                resourceAttrList = CollectionUtil.unionAll(resourceAttrList, answerAttrs);
            }
            if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(descriptionAttrs)) {
                resourceAttrList = CollectionUtil.unionAll(resourceAttrList, descriptionAttrs);
            }

            List<PaperItemFile> paperItemFiles = new ArrayList<>();
            if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(resourceAttrList)) {
                for (ResourceAttr item : resourceAttrList) {
                    PaperItemFile paperItemFile = new PaperItemFile();
                    paperItemFile.setFileLocation(item.getType());
                    paperItemFile.setFileType(item.getFileType());
                    paperItemFile.setItemId(itemDataDTO.getItemId());
                    paperItemFile.setPaperId(paper.getPaperId());
                    paperItemFile.setPaperVersion(paper.getPaperVersion());
                    paperItemFile.setSort(item.getOptionSort());
                    paperItemFile.setUrl(item.getUrl());
                    paperItemFile.setProjectId(paper.getProjectId());
                    paperItemFiles.add(paperItemFile);
                }
                paperItemFileService.saveBatch(paperItemFiles);
            }
        }
    }

    /**
     * 初始化大题
     *
     * @param paperItemId
     * @param topicDataDTO
     * @param paperItems
     * @param paper
     */
    private void addChildItems(String paperItemId, TopicDataDTO topicDataDTO, List<PaperItem> paperItems, Paper paper) {
        String paperId = paper.getId();
        List<ItemDataDTO> itemDataVOS = topicDataDTO.getItemDataList();
        for (ItemDataDTO itemDataDTO : itemDataVOS) {
            PaperItem bigItem = new PaperItem();
            bigItem.setId(UUIDUtils.newSortUUID());
            bigItem.setTopicId(itemDataDTO.getItemId());
            bigItem.setPaperId(paperId);
            bigItem.setParentId(paperItemId);
            // 大题没有名称
            // itemCode
            bigItem.setItemCode(itemDataDTO.getSort().toString());
            bigItem.setIsComposite(itemDataDTO.getComposite());
            String itemType = itemDataDTO.getItemType();
            bigItem.setItemType(itemType);
            bigItem.setItemLevel(1);
            // TODO 大题是否需要标明主客观
            bigItem.setItemViewPoint(itemDataDTO.getObjective());
            bigItem.setItemStem(itemDataDTO.getItemContent());
            bigItem.setAnswer(itemDataDTO.getAnswer());
            bigItem.setAnalysis(itemDataDTO.getDescription());
            bigItem.setOrderNum(itemDataDTO.getSort());
            if (itemDataDTO.getScore() != null) {
                bigItem.setScore(new BigDecimal(itemDataDTO.getScore()));
            }
            paperItems.add(bigItem);
            if ("fill_in_blanks".equalsIgnoreCase(itemType)) {
                List<OptionsDataDTO> optionsDataDTOS = itemDataDTO.getOptionsDataList();
                for (OptionsDataDTO optionsDataDTO : optionsDataDTOS) {
                    PaperItem optionItem = new PaperItem();
                    optionItem.setId(UUIDUtils.newSortUUID());
                    optionItem.setTopicId(optionsDataDTO.getOptionId());
                    optionItem.setPaperId(paperId);
                    optionItem.setParentId(bigItem.getId());
                    // 大题没有名称
                    optionItem.setItemName(optionsDataDTO.getOptionName());
                    // itemCode
                    optionItem.setIsComposite(optionsDataDTO.getComposite());
                    optionItem.setItemType("option");
                    optionItem.setItemLevel(2);
                    // TODO 大题是否需要标明主客观
                    optionItem.setItemViewPoint(false);
                    optionItem.setItemStem(optionsDataDTO.getOptionContent());
                    String optionScore = optionsDataDTO.getScore();
                    optionItem.setOrderNum(optionsDataDTO.getSort());
                    if (optionScore != null) {
                        optionItem.setScore(new BigDecimal(optionScore));
                    }
                    paperItems.add(optionItem);
                }
            } else {
                List<ItemDataDTO> childItemList = itemDataDTO.getChildItemList();
                // 保存复合题的音视频
                savePaperItemFile(childItemList, paper);
                for (ItemDataDTO childItem : childItemList) {
                    PaperItem subItem = new PaperItem();
                    subItem.setId(UUIDUtils.newSortUUID());
                    subItem.setTopicId(childItem.getItemId());
                    subItem.setPaperId(paperId);
                    subItem.setParentId(bigItem.getId());
                    // 大题没有名称
                    subItem.setItemCode(childItem.getSort().toString());
                    subItem.setIsComposite(childItem.getComposite());
                    String subItemType = childItem.getItemType();
                    subItem.setItemType(subItemType);
                    subItem.setItemLevel(2);
                    // TODO 大题是否需要标明主客观
                    subItem.setItemViewPoint(childItem.getObjective());
                    subItem.setItemStem(childItem.getItemContent());
                    subItem.setAnswer(childItem.getAnswer());
                    subItem.setAnalysis(childItem.getDescription());
                    subItem.setOrderNum(childItem.getSort());
                    if (childItem.getScore() != null) {
                        subItem.setScore(new BigDecimal(childItem.getScore()));
                    }
                    paperItems.add(subItem);
                    if ("fill_in_blanks".equalsIgnoreCase(subItemType)) {
                        List<OptionsDataDTO> optionsDataDTOS = itemDataDTO.getOptionsDataList();
                        for (OptionsDataDTO optionsDataDTO : optionsDataDTOS) {
                            PaperItem optionItem = new PaperItem();
                            optionItem.setId(UUIDUtils.newSortUUID());
                            optionItem.setTopicId(optionsDataDTO.getOptionId());
                            optionItem.setPaperId(paperId);
                            optionItem.setParentId(optionsDataDTO.getItemId());
                            // 大题没有名称
                            optionItem.setItemName(optionsDataDTO.getOptionName());
                            // itemCode
                            optionItem.setIsComposite(optionsDataDTO.getComposite());
                            optionItem.setItemType("option");
                            optionItem.setItemLevel(2);
                            // TODO 大题是否需要标明主客观
                            optionItem.setItemViewPoint(false);
                            optionItem.setItemStem(optionsDataDTO.getOptionContent());
                            optionItem.setOrderNum(optionsDataDTO.getSort());
                            if (optionsDataDTO.getScore() != null) {
                                optionItem.setScore(new BigDecimal(optionsDataDTO.getScore()));
                            }
                            paperItems.add(optionItem);
                        }
                    }
                }
            }
        }
    }

    /**
     * 生成评卷块
     *
     * @param paperAndItemDataDTO
     */
    private Piece transferAndSavePiece(PaperAndItemDataDTO paperAndItemDataDTO, PjProjectInfoDTO pjProjectInfoDTO, String examId) {
        Paper paper = paperAndItemDataDTO.getPaper();
        List<PaperItem> paperItems = paperAndItemDataDTO.getPaperItems();
        // 插入piece表
        // 主
        Piece pieceProject = new Piece();
        pieceProject.setProjectId(examId);
        pieceProject.setSubjectId(paper.getSubjectId());
        pieceProject.setParentId(Constants.COMMON_PARENT_ID);
        pieceProject.setPieceName(pjProjectInfoDTO.getBatchName());
        pieceProject.setPieceType(CommonEnums.PIECE_TYPE_1.getCode());
        pieceService.save(pieceProject);
        // 子
        Piece piecePaper = new Piece();
        piecePaper.setProjectId(examId);
        piecePaper.setSubjectId(paper.getSubjectId());
        piecePaper.setParentId(pieceProject.getId());
        piecePaper.setPieceName(paper.getPaperName());
        piecePaper.setPieceType(CommonEnums.PIECE_TYPE_2.getCode());
        piecePaper.setPaperId(paper.getId());
        pieceService.save(piecePaper);

        // 插入piece_item表
        List<PieceItem> pieces = new ArrayList<>();
        for (PaperItem paperItem : paperItems) {
            PieceItem pieceItem = new PieceItem();
            pieceItem.setPieceId(piecePaper.getId());
            pieceItem.setItemId(paperItem.getTopicId());
            pieces.add(pieceItem);
        }
        pieceItemService.saveBatch(pieces);
        // 这里返回的是和科目挂钩的piece，由于只有一个科目所以返回一个对象
        return piecePaper;
    }

    /**
     * 根据项目id删除项目下所有数据
     *
     * @param projectId
     */
    private void deleteProjectAllData(String projectId) {
        // 1、清除项目信息
        projectService.removeById(projectId);

        // 2、清除科目数据
        subjectService.remove(new LambdaQueryWrapper<Subject>().eq(Subject::getProjectId, projectId));

        // 3、清除试卷数据
        List<Paper> paperList = paperService.lambdaQuery().eq(Paper::getProjectId, projectId).list();
        paperService.remove(new LambdaQueryWrapper<Paper>().eq(Paper::getProjectId, projectId));
        for (Paper paper : paperList) {
            paperItemService.remove(new LambdaQueryWrapper<PaperItem>().eq(PaperItem::getPaperId, paper.getPaperId()));
        }

        // 4、清除考生信息和task信息
        studentService.remove(new LambdaQueryWrapper<Student>().eq(Student::getProjectId, projectId));
        taskService.remove(new LambdaQueryWrapper<Task>().eq(Task::getProjectId, projectId));
        subjectScoreService.remove(new LambdaQueryWrapper<SubjectScore>().eq(SubjectScore::getProjectId, projectId));
        studentConfigService.remove(new LambdaQueryWrapper<StudentConfig>().eq(StudentConfig::getProjectId, projectId));

        // 5、清除评卷块
        List<Piece> pieceList = pieceService.lambdaQuery().eq(Piece::getProjectId, projectId).list();
        pieceService.remove(new LambdaQueryWrapper<Piece>().eq(Piece::getProjectId, projectId));
        for (Piece piece : pieceList) {
            pieceItemService.remove(new LambdaQueryWrapper<PieceItem>().eq(PieceItem::getPieceId, piece.getId()));
        }

        // 6、清除附件信息
        paperItemFileService.remove(new LambdaQueryWrapper<PaperItemFile>().eq(PaperItemFile::getProjectId, projectId));
    }

}
